package com.ironman.imes.device.data.source.verticles;

import cn.hutool.core.util.StrUtil;
import com.ironman.imes.device.data.source.BaseSource;
import com.ironman.imes.device.event.model.DeviceSourceData;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.noear.snack.ONode;

import java.util.List;


@Slf4j
@RequiredArgsConstructor
public class HttpServerVerticle extends AbstractVerticle implements BaseSource {

    private final String name;

    private final String host;

    private final int port;

    private final List<ONode> api;

    private HttpServer httpServer;

    @Override
    public void start(Promise<Void> startPromise) {
        // 创建 HTTP 服务器
        this.httpServer = vertx.createHttpServer();

        // 创建路由器
        Router router = Router.router(vertx);

        // 解析请求体
        router.route().handler(BodyHandler.create());

        // 全局日志中间件
        router.route().handler(ctx -> {
            log.info("{}=>{} {} ", name, ctx.request().method(), ctx.request().path());
            ctx.next();
        });

        for (ONode apiNode : api) {
            String uri = apiNode.get("uri").getString();
            String method = apiNode.get("method").getString();
            ONode meta = apiNode.get("meta");
            ONode response = apiNode.get("response");
            router.route(HttpMethod.valueOf(method.toUpperCase()), uri).handler(new Handler<RoutingContext>() {
                @Override
                public void handle(RoutingContext event) {
                    String body = event.body().asString();
                    ONode bodyNode = ONode.loadStr(body);

                    String deviceType = null;
                    String deviceTypeKey = meta.select("$.deviceType.query").getString();
                    if (StrUtil.isNotBlank(deviceTypeKey)) {
                        MultiMap queryParams = event.queryParams();
                        deviceType = queryParams.get(deviceTypeKey);
                    }
                    deviceTypeKey = meta.select("$.deviceType.path").getString();
                    if (StrUtil.isBlank(deviceType) && StrUtil.isNotBlank(deviceTypeKey)) {
                        deviceType = event.pathParam(deviceTypeKey);
                    }

                    deviceTypeKey = meta.select("$.deviceType.body").getString();
                    if (StrUtil.isBlank(deviceType) && StrUtil.isNotBlank(deviceTypeKey)) {
                        deviceType = bodyNode.select(deviceTypeKey).getString();
                    }

                    String deviceCode = null;
                    String deviceCodeKey = meta.select("$.deviceCode.query").getString();
                    if (StrUtil.isNotBlank(deviceCodeKey)) {
                        MultiMap queryParams = event.queryParams();
                        deviceCode = queryParams.get(deviceCodeKey);
                    }
                    deviceCodeKey = meta.select("$.deviceCode.path").getString();
                    if (StrUtil.isBlank(deviceCode) && StrUtil.isNotBlank(deviceCodeKey)) {
                        deviceCode = event.pathParam(deviceCodeKey);
                    }
                    deviceCodeKey = meta.select("$.deviceCode.body").getString();
                    if (StrUtil.isBlank(deviceCode) && StrUtil.isNotBlank(deviceCodeKey)) {
                        deviceCode = bodyNode.select(deviceCodeKey).getString();
                    }

                    log.info("设备类型 {}, 设备编号 {}", deviceType, deviceCode);
                    log.info("请求体 {}", body);
                    launchData(new DeviceSourceData(uri, deviceType, deviceCode, body));

                    HttpServerResponse httpServerResponse = event.response();
                    List<ONode> header = response.select("$.header").ary();
                    for (ONode node : header) {
                        httpServerResponse.putHeader(node.get("name").getString(), node.get("value").getString());
                    }
                    httpServerResponse.end(response.select("$.body").getString());
                }
            });
        }

        // 启动服务器
        httpServer.requestHandler(router)
                .listen(port, host, event -> {
                    if (event.succeeded()) {
                        startPromise.complete();
                    } else {
                        startPromise.fail(event.cause());
                    }
                });
    }

    @Override
    public void stop(Promise<Void> stopPromise) {
        httpServer.close(event -> {
            if (event.succeeded()) {
                stopPromise.complete();
            } else {
                stopPromise.fail(event.cause());
            }
        });
    }
}